//Tyler's Notes:
//started states but need to rethink the logic I was using might be a good base for loads
//for unload I think you just do passengers.top()->setExit(time); ticketHand->closeTicket; passengers.pop(); the rest should be simple logic to figure out

#pragma once
#include <iostream>
#include "Elevator.h"

#define FLOOR_CHANGE_TIME 15
#define DOOR_OPEN_TIME 3
#define PASSENGER_LOAD_TIME 3
#define IDLE_TIME 10
#define MAX_PASSENGERS 8

//if passanger is stranded (stuck in elevator) this is the time they get
#define strandedTime -1

Elevator::Elevator(vector <Floor>* floorVector,TicketHandler * tickets,int elevatorID)
{
	ticketHand = tickets;
	floors = floorVector;
	elID = elevatorID;
}


Elevator::~Elevator(void)
{
	//clearing passengers and setting them as stranded
	while(!passengers.empty())
	{
		passengers.pop();
	}
}


void Elevator::init(void)
{
	timer = 0;
	curentFloor = 0;
	targetFloor = 0;
	curState = IDLE;
	//clearing passengers and setting them as stranded
	while(!passengers.empty())
	{
		passengers.pop();
	}
}


void Elevator::loadPassenger(Ticket ** tickload, int theTime)
{
	Ticket* tempTick;
	tempTick = *tickload;
	tempTick->setElevator(elID);
	tempTick->setExitTime(strandedTime);
	tempTick->setService(theTime);
	passengers.push(tempTick);
	targetFloor = passengers.top()->getDestination();
	timer = PASSENGER_LOAD_TIME;
}

void Elevator::unloadPassenger(int time)
{
	passengers.top()->setExitTime(time);
	ticketHand->ticketClosed();
	passengers.pop();
	if(!passengers.empty())
	{
		targetFloor = passengers.top()->getDestination();
	}
	timer = PASSENGER_LOAD_TIME;
}


void Elevator::update(int time)
{
	Ticket* tempTick;
	tempTick = 0;
	// Walker: need additional variable
	//Ticket ** tickptr = &tempTick;
	if(timer>0)
		--timer;
	switch(curState)
	{
	case IDLE:
		for(int i = floors->size()-1;i>-1;--i)
		{
			if(floors->at(i).isCallPressed(elID))
			{
				targetFloor = i;
				if(i == 0)
				{
					curState = FIRST_FLR_LOAD;
					if(floors->at(0).getTicket(&tempTick,elID))//CHANGE THIS!!!
						//if(floors->at(0).getTicket(tickptr,elID))
					{
						loadPassenger(&tempTick,time);
						/*passengers.push(tempTick;
						tempTick->setElevator(elID);
						tempTick->setExitTime(strandedTime);
						tempTick->setService(time);
						timer = PASANGER_LOAD_TIME;*/
						curState = FIRST_FLR_LOAD;

					}
					else
					{
						cout<<"Ground floor Error\n";
					}
				}
				else
				{
					timer = FLOOR_CHANGE_TIME;
					curState = MOVE_UP_EMPTY;
				}
				break;
			}
		}
		break;
	case FIRST_FLR_DELAY:
		if(floors->at(0).getTicket(&tempTick,elID))//CHANGE THIS!!!
			//if(floors->at(0).getTicket(tickptr,elID))
		{	
			loadPassenger(&tempTick,time);
			/*passengers.push(tempTick);
			tempTick->setElevator(elID);
			tempTick->setExitTime(strandedTime);
			tempTick->setService(time);
			timer = PASANGER_LOAD_TIME;*/
			curState = FIRST_FLR_LOAD;

		}
		else
		{
			if(timer == 0)
			{
				if(!passengers.empty())
				{
					targetFloor = passengers.top()->getDestination();
					timer = FLOOR_CHANGE_TIME;
					curState = MOVE_UP_OCC;
					floors->at(curentFloor).elevatorLeaving(elID);
				}
				else
				{
					curState = IDLE;
					floors->at(curentFloor).elevatorLeaving(elID);
				}
			}
		}
		break;
	case UPPER_FLR_DELAY:
		if(floors->at(curentFloor).getTicket(&tempTick,elID))//CHANGE THIS!!!
			//if(floors->at(0).getTicket(tickptr,elID))
		{
			loadPassenger(&tempTick,time);
			/*passengers.push(tempTick);
			tempTick->setElevator(elID);
			tempTick->setExitTime(strandedTime);
			tempTick->setService(time);
			timer = PASANGER_LOAD_TIME;*/
			curState = UPPER_FLR_LOAD;
		}
		else
		{
			if(timer == 0)
			{
				targetFloor = 0;
				timer = FLOOR_CHANGE_TIME;
				if(passengers.size()<MAX_PASSENGERS)
				{
					curState = MOVE_DOWN_NOT_FULL;
					floors->at(curentFloor).elevatorLeaving(elID);
				}
				else
				{
					curState = MOVE_DOWN_FULL;
					floors->at(curentFloor).elevatorLeaving(elID);
				}
			}
		}
		break;
	case UPPER_FLR_DELAY_OCC_UP:
		if(timer == 0)
		{
			targetFloor = passengers.top()->getDestination();
			timer = FLOOR_CHANGE_TIME;
			curState = MOVE_UP_OCC;
			floors->at(curentFloor).elevatorLeaving(elID);
		}
		break;
	case UPPER_FLR_DELAY_OCC_DOWN:
		if(timer == 0)
		{
			timer = FLOOR_CHANGE_TIME;
			curState = MOVE_DOWN_NOT_FULL;
			floors->at(curentFloor).elevatorLeaving(elID);
		}
		break;
	case FIRST_FLR_LOAD:
		if(timer == 0)
		{
			if(passengers.size()<MAX_PASSENGERS)
			{
				if(floors->at(curentFloor).getTicket(&tempTick,elID))
				{
					loadPassenger(&tempTick,time);
				}
				else
				{
					timer = IDLE_TIME;
					curState = FIRST_FLR_DELAY;
				}
			}
			else
			{
				floors->at(curentFloor).elevatorLeaving(elID);
				timer = FLOOR_CHANGE_TIME;
				curState = MOVE_UP_OCC;
			}
		}
		break;
	case UPPER_FLR_LOAD:
		if(timer == 0)
		{
			if(passengers.size()<MAX_PASSENGERS)
			{
				if(floors->at(curentFloor).getTicket(&tempTick,elID))
				{
					loadPassenger(&tempTick,time);
				}
				else
				{
					timer = IDLE_TIME;
					curState = UPPER_FLR_DELAY;
				}
			}
			else
			{
				floors->at(curentFloor).elevatorLeaving(elID);
				timer = FLOOR_CHANGE_TIME;
				curState = MOVE_DOWN_FULL;
			}
		}
		break;
	case FIRST_FLR_UNLOAD:
		if(timer == 0)
		{
			if(!passengers.empty())
			{
				unloadPassenger(time);
			}
			else
			{
				curState = IDLE;
			}
		}
		break;
	case UPPER_FLR_UNLOAD:
		if(timer == 0)
		{
			if(!passengers.empty())
			{
				if(passengers.top()->getDestination() == curentFloor)
				{
					unloadPassenger(time);
				}
				else
				{
					targetFloor = passengers.top()->getDestination();
					curState = UPPER_FLR_DELAY_OCC_UP;
					timer = IDLE_TIME;
				}
			}
			else
			{
				targetFloor = 0;
				curState = UPPER_FLR_DELAY_OCC_DOWN;
			}
		}
		break;
	case MOVE_UP_EMPTY:
		if(timer == 0)
		{
			++curentFloor;
			if(curentFloor==targetFloor)
			{
				if(floors->at(curentFloor).getTicket(&tempTick,elID))
				{
					loadPassenger(&tempTick,time);
					curState = UPPER_FLR_LOAD;
				}
				else
				{
					timer = IDLE_TIME;
					curState = UPPER_FLR_DELAY;
				}
			}
			else
			{
				if(curentFloor<floors->size()-1)
				{
					timer = FLOOR_CHANGE_TIME;
				}
				else
				{
					targetFloor = 0;
					curState = MOVE_DOWN_NOT_FULL;
					timer = FLOOR_CHANGE_TIME;
				}
			}
		}
		break;
	case MOVE_UP_OCC:
		if(timer == 0)
		{
			++curentFloor;
			if(curentFloor == targetFloor)
			{
				unloadPassenger(time);
				curState = UPPER_FLR_UNLOAD;
			}
			else
			{
				if(curentFloor<floors->size()-1)
				{
					timer = FLOOR_CHANGE_TIME;
				}
				else
				{
					targetFloor = passengers.top()->getDestination();
					timer = FLOOR_CHANGE_TIME;
					if(passengers.size()<MAX_PASSENGERS)
					{
						curState = MOVE_DOWN_NOT_FULL;
					}
					else
					{
						curState = MOVE_DOWN_FULL;
					}
				}
			}
		}
		break;
	case MOVE_DOWN_NOT_FULL:
		if(timer == 0)
		{
			--curentFloor;
			if(curentFloor == 0)
			{
				if(!passengers.empty())
				{
					unloadPassenger(time);
					curState = FIRST_FLR_UNLOAD;
				}
				else
				{
					curState = IDLE;
				}
			}
			else
			{
				if(floors->at(curentFloor).getTicket(&tempTick,elID))
				{
					loadPassenger(&tempTick,time);
					curState = UPPER_FLR_LOAD;
				}
				else
				{
					timer = FLOOR_CHANGE_TIME;
				}
			}
		}
		break;
	case MOVE_DOWN_FULL:
		if(timer == 0)
		{
			--curentFloor;
			if(curentFloor == 0)
			{
				if(!passengers.empty())
				{
					unloadPassenger(time);
					curState = FIRST_FLR_UNLOAD;
				}
				else
				{
					curState = IDLE;
				}
			}
			else
			{
				timer = FLOOR_CHANGE_TIME;
			}
		}
		break;
	}
}
// Walker: proposed new private helper method
//// Private method to load a passenger
//void Elevator::loadPassenger(Ticket * tick, int elID, int theTime)
//{
//	tick->setElevator(elID);
//	tick->setExitTime(strandedTime);
//	tick->setService(theTime);
//	timer = PASANGER_LOAD_TIME;
//}
// Tyler: used this idea but removed the int elID arg since its a private var that the function can already touch